package com.android.samples.mediastore.hms.drive.utils

import android.content.Intent
import android.text.TextUtils
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.load.model.Headers
import com.bumptech.glide.load.model.LazyHeaders
import com.huawei.cloud.services.drive.DriveScopes
import com.huawei.hms.support.account.AccountAuthManager
import com.huawei.hms.support.account.request.AccountAuthParams
import com.huawei.hms.support.account.request.AccountAuthParamsHelper
import com.huawei.hms.support.account.result.AuthAccount
import com.huawei.hms.support.account.service.AccountAuthService
import com.huawei.hms.support.api.entity.auth.Scope
import java.util.*
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock


object HmsSigninUtils {

    // Get AT Lock
    private val getATLock = ReentrantLock()

    // HuaweiIdAuthService  object
    private var service: AccountAuthService? = null

    // HuaweiIdAuthParams  object
    private var authParams: AccountAuthParams?

    // AccessToken
    var accessToken: String? = null
        private set

    // UnionId
    var unionId: String? = null

    // DeviceId
    var deviceId: String? = null
        private set

    // DisplayName
    var displayName: String? = null
        private set

    // Status
    var status = 0
        private set

    // Gender
    var gender = 0
        private set

    // GrantedScopes
    var grantedScopes: Set<*>? = null
        private set

    // ServiceCountryCode
    var serviceCountryCode: String? = null
        private set

    /**
     * Get accessToken
     */
    private val aT: Unit
        get() {
            for (retry in 0..1) {
                Log.i(TAG, "signInBackend times: $retry")
                if (signInBackend()) {
                    break
                }
            }
        }
    private const val TAG = "HmsProxyImpl"

    init {
        authParams =
            initData()
    }

    /**
     * Initialize and return the HuaweiIdSignInOptions object
     */
    private fun initData(): AccountAuthParams {
        val scopeList: MutableList<Scope> = LinkedList()
        scopeList.add(Scope(DriveScopes.SCOPE_DRIVE_FILE))
        scopeList.add(Scope(DriveScopes.SCOPE_DRIVE_APPDATA))
        return AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAccessToken()
            .setAuthorizationCode().setIdToken()
            .setScopeList(scopeList).createParams()
    }

    /**
     * Huawei Api Client authorized login method
     *
     * @param activity Call the Activity page handle of the singIn interface
     */
    fun singIn(activity: AppCompatActivity, hmsSignInLauncher: ActivityResultLauncher<Intent>) {
        if (authParams == null) {
            authParams =
                initData()
        }
        service = AccountAuthManager.getService(
            activity,
            authParams
        )
        hmsSignInLauncher.launch(service?.signInIntent)
    }


    /**
     * Synchronously acquire access token, must be called in non-main thread
     *
     * @return accessToken or `null`
     */
    fun refreshAccessToken(): String? {
        Log.i(TAG, "refreshAccessToken begin")
        try {
            if (service != null) {
                getATLock.lock()
                try {
                    aT
                } finally {
                    getATLock.unlock()
                }
                Log.d(TAG, "refreshAccessToken return new")
            } else {
                Log.e(TAG, "refreshAccessToken client is null, return null")
            }
        } catch (e: Exception) {
            Log.e(TAG, "refreshAccessToken exception, return null")
        }
        Log.i(TAG, "refreshAccessToken end")
        return accessToken
    }

    /**
     * Sign in Background
     */
    private fun signInBackend(): Boolean {
        Log.i(TAG, "signInBackend")
        clearAccountInfo()
        if (service == null) {
            return false
        }
        val countDownLatch = CountDownLatch(1)
        val task = service!!.silentSignIn()
        task.addOnSuccessListener { authAccount ->
            Log.i(TAG, "silentSignIn success")
            dealSignInResult(
                authAccount
            )
            countDownLatch.countDown()
        }
        task.addOnFailureListener {
            Log.i(TAG, "silentSignIn error")
            countDownLatch.countDown()
        }
        try {
            countDownLatch.await(15, TimeUnit.SECONDS)
        } catch (e: InterruptedException) {
            Log.i(TAG, "signInBackend catch InterruptedException")
            countDownLatch.countDown()
        }
        return !TextUtils.isEmpty(accessToken)
    }

    /**
     * Process certification results
     */
    fun dealSignInResult(authAccount: AuthAccount) {
        val tempAt = authAccount.getAccessToken()
        if (null == tempAt || tempAt.isEmpty()) {
            Log.e(TAG, "dealSignInResult get accessToken is null.")
            return
        }
        Log.i(TAG, "dealSignInResult signInBackend get new AT successfully")
        saveAccountInfo(
            authAccount
        )
    }

    /**
     * Save account info
     */
    private fun saveAccountInfo(authAccount: AuthAccount?) {
        if (authAccount == null) {
            return
        }
        unionId = authAccount.getUnionId()
        deviceId = authAccount.getOpenId()
        displayName = authAccount.getDisplayName()
        status = authAccount.getStatus()
        gender = authAccount.getGender()
        grantedScopes = authAccount.authorizedScopes
        serviceCountryCode = authAccount.getServiceCountryCode()
        accessToken = authAccount.getAccessToken()
        Log.e(TAG, "saveAccountInfo:  accessToken = $accessToken")
        headers = LazyHeaders.Builder().addHeader("Authorization", "Bearer $accessToken").build()
    }

    /**
     * Clear account info
     */
    private fun clearAccountInfo() {
        unionId = null
        deviceId = null
        displayName = null
        status = 0
        gender = 0
        grantedScopes = null
        serviceCountryCode = null
        accessToken = null
    }

    lateinit var headers: Headers
        private set


}